package com.everydayflash.fp10 {
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.display.TriangleCulling;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.PerspectiveProjection;
	import flash.geom.Vector3D;	

	/**
	 * @author bartekd
	 */
	public class TexturedCube extends Sprite {

		private var vertices:Vector.<Vector3D>;
		private var indices:Vector.<int>;
		private var idn:Vector.<int>;
		
		private var proj:PerspectiveProjection;
		private var projm:Matrix3D;
		
		private var cycle:Number = 0;
		private var angle:Number = 0;

		[Embed (source="stone.jpg")]
		private var PerlinTexture:Class;
		
		private var box3D:Sprite;

		public function TexturedCube() {
			stage.quality = StageQuality.MEDIUM;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.showDefaultContextMenu = false;
			stage.stageFocusRect = false;
			
			vertices = new Vector.<Vector3D>();
			
			var size:Number = 100;

			vertices.push(new Vector3D(-size, -size, size, 1));			vertices.push(new Vector3D(size, -size, size, 1));			vertices.push(new Vector3D(size, size, size, 1));			vertices.push(new Vector3D(-size, size, size, 1));
			vertices.push(new Vector3D(-size, -size, -size, 1));
			vertices.push(new Vector3D(size, -size, -size, 1));
			vertices.push(new Vector3D(size, size, -size, 1));
			vertices.push(new Vector3D(-size, size, -size, 1));

			proj = new PerspectiveProjection();
			proj.focalLength = 300;
			projm = proj.toMatrix3D();

			indices = new Vector.<int>();

			indices.push(0, 1, 3);
			indices.push(3, 1, 2);

			indices.push(4, 7, 5);
			indices.push(5, 7, 6);

			indices.push(0, 4, 1);
			indices.push(1, 4, 5);

			indices.push(2, 6, 3);
			indices.push(3, 6, 7);

			indices.push(1, 5, 2);
			indices.push(2, 5, 6);
			
			indices.push(0, 3, 4);
			indices.push(4, 3, 7);

			idn = new Vector.<int>();
			for (var j:int = 0;j < indices.length; j++) idn.push(j);

			box3D = new Sprite();
			box3D.x = stage.stageWidth / 2;
			box3D.y = stage.stageHeight / 2;
			addChild(box3D);

			addEventListener(Event.ENTER_FRAME, render);
		}

		private function render(event:Event):void {
			var vs:Vector.<Number> = new Vector.<Number>();
			var uvts:Vector.<Number> = new Vector.<Number>();
			var uv:Vector.<Number> = new Vector.<Number>();
			
			var m:Matrix3D = new Matrix3D();
			m.appendRotation(angle, new Vector3D(0, 1, 0));			m.appendRotation(angle / 2, new Vector3D(1, 0, 0));
			m.appendTranslation(0, 0, 300);
	
			for (var i:int = 0;i < indices.length; i++) {
				var v:Vector3D = vertices[indices[i]];
				v = m.transformVector(v);
				v = projm.transformVector(v);
				v.project();
				uvts.push(proj.focalLength / v.w);
				vs.push(v.x, v.y);
			}
			
			
			for (var k:int = 0;k < indices.length; k += 6) {
				uvSet(uvts, uv, k);
			}

			cycle += .3;
			angle = 360 * Math.sin(Math.PI * 2 * (1 - ((cycle % 360) / 360)));
			
			box3D.graphics.clear();
			box3D.graphics.beginBitmapFill(new PerlinTexture().bitmapData, null, false, false);
			box3D.graphics.drawTriangles(vs, idn, uv, TriangleCulling.POSITIVE);
			box3D.graphics.endFill();
		}

		private function uvSet(uvts:Vector.<Number>, uv:Vector.<Number>, a:int):void {
			uv.push(0, 0, uvts[a], 0, 1, uvts[a + 1], 1, 0, uvts[a + 2]);			uv.push(1, 0, uvts[a + 3], 0, 1, uvts[a + 4], 1, 1, uvts[a + 5]);
		}
	}
}












